﻿/**	@file		swap_list.hpp
 *	@date		(2006-10-30 21:47:39)/(2009-01-03 15:21:41)
 *-----------------------------------------------------------------------------
 *	\brief		交换链表.
 *	@version	1.0.14.19
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/


#if			!defined(__LOLIX__LOLI__SWAP_LIST__K_IN_G__)
#define		__LOLIX__LOLI__SWAP_LIST__K_IN_G__
//==============================================================================
//--------------------------------------------------------------------------


#if			!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
	#include	"../lolix_macro.h"
#endif	//	!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
#if			!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)
	#include	"../toy/allocator.h"
#endif	//	!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)
#if			!defined(__LOLIX__TOY__STD_LIST__NICK__K_IN_G__)
	#include	"../toy/std_list.hpp"
#endif	//	!defined(__LOLIX__TOY__STD_LIST__NICK__K_IN_G__)
#if			!defined(__LOLIX__LOLI__CRITICAL_SECTION__K_IN_G__)
	#include	"./critical_section.h"
#endif	//	!defined(__LOLIX__LOLI__CRITICAL_SECTION__K_IN_G__)
#if			!defined(__LOLIX__LOLI__SIGNAL__H__K_IN_G__)
	#include	"./signal.h"
#endif	//	!defined(__LOLIX__LOLI__SIGNAL__H__K_IN_G__)




namespace lolix{
	namespace loli{
		namespace _help{
			template<typename _TyF, typename _TyB>
			struct	get_default_type;
			template<bool is_cs>
			class	_LOGIC_CS;
		}
		LOLIX_TRACE_ALLOC_TYPEDEF("lolix::loli::swap_list", __ALLOC__LOLIX__LOLI__SWAP_LIST__H__);
		template<typename _TyF, typename _TyB = void, lolix::ENUM_THREAD_SAFE = lolix::THREAD_SAFE_SRSW, typename _TAlloc = __ALLOC__LOLIX__LOLI__SWAP_LIST__H__ >
		class	swap_list;
		template<typename _TyF, typename _TyB, typename _CS_BACK, typename _CS_FRONT, typename _CS_SWAP, typename _TAlloc>
		class	_swap_list;
	}
}


template<typename _TyF, typename _TyB>
struct	lolix::loli::_help::get_default_type
{
	typedef	_TyF	frnt_type;
	typedef	_TyB	back_type;
};


template<typename _TyF>
struct	lolix::loli::_help::get_default_type<_TyF, void>
{
	typedef _TyF	frnt_type;
	typedef	_TyF	back_type;
};


template<typename _TyB>
struct	lolix::loli::_help::get_default_type<void, _TyB>
{
	typedef	_TyB	frnt_type;
	typedef	_TyB	back_type;
};


template<bool is_cs>
class	lolix::loli::_help::_LOGIC_CS
{
	CANNT_COPY_LOLI;
	mutable lolix::loli::critical_section*	_cs;
public:
	explicit LOLIX_INLINE_CALL	_LOGIC_CS<is_cs>(lolix::loli::critical_section* cs)
		: _cs(cs)
		{
		_cs->inc_ref();
		}
	LOLIX_INLINE_CALL	_LOGIC_CS<is_cs>(const _LOGIC_CS<is_cs>& o)
		: _cs(o._cs)
		{
		_cs->inc_ref();
		}

	LOLIX_INLINE_CALL	~_LOGIC_CS<is_cs>(void)
		{
		_cs->release();
		}

	LOLIX_INLINE_CALL	LOLIX_RETNV	enter(void)
		{
		return _cs->enter();
		}

	LOLIX_INLINE_CALL	LOLIX_RETNV	leave(void)
		{
		return _cs->leave();
		}
};

template<>
class	lolix::loli::_help::_LOGIC_CS<false>
{
	CANNT_COPY_LOLI;
	THREAD_ZONE	_tz;
public:
	_LOGIC_CS<false>(void){}
	_LOGIC_CS<false>(const _LOGIC_CS<false>&){}

	LOLIX_INLINE_CALL	LOLIX_RETNV	enter(void)
		{
		TOUCH_THREAD_ZONE(_tz);
		return lolix::LOLIX_RETNV_OK;
		}
	LOLIX_INLINE_CALL	LOLIX_RETNV	leave(void)
		{
		TOUCH_THREAD_ZONE(_tz);
		return lolix::LOLIX_RETNV_OK;
		}
};





template<typename _ITyF, typename _ITyB, typename _TAlloc>
class lolix::loli::swap_list<_ITyF, _ITyB, lolix::THREAD_SAFE_SRSW, _TAlloc>
{
	CANNT_COPY_LOLI;
/////////////////////////////////////////////////////////////
//				send					get
//	frnt		_frnt._lt_frnt			_back._lt_frnt
//
//	back		_back._lt_back			_frnt._lt_back

	typedef	typename _help::get_default_type<_ITyF, _ITyB>::frnt_type	_TyF;
	typedef	typename _help::get_default_type<_ITyF, _ITyB>::back_type	_TyB;

	typedef swap_list<_ITyF, _ITyB, lolix::THREAD_SAFE_SRSW, _TAlloc>	this_type;
	typedef typename lolix::type::type_def<_TyF>::const_reference		t_frnt_const_pass_value;
	typedef typename lolix::type::type_def<_TyB>::const_reference		t_back_const_pass_value;
public:
	typedef	_TAlloc	allocator_type;
	typedef size_type	size_type;
	typedef _TyF	front_value_type;
	typedef _TyB	back_value_type;
	enum { THREAD_SAFE_TYPE = THREAD_SAFE_SRSW };
#if			1
	explicit swap_list(lolix::loli::critical_section* cs)
		: _cs(cs)
		, _frnt()
		, _back()
	{
		_cs->inc_ref();
	}

	swap_list(critical_section* cs, signal* wait_frnt, signal* wait_back)
		: _cs(cs)
		, _frnt(wait_back)
		, _back(wait_frnt)
	{
		_cs->inc_ref();
	}

	swap_list(critical_section* cs, const _TAlloc& alc)
		: _cs(cs)
		, _frnt(alc)
		, _back(alc)
	{
		_cs->inc_ref();
	}

	swap_list(critical_section* cs, signal* wait_frnt, signal* wait_back, const _TAlloc& alc)
		: _cs(cs)
		, _frnt(wait_back, alc)
		, _back(wait_frnt, alc)
	{
		_cs->inc_ref();
	}

	~swap_list(void)
	{
		_cs->release();
	}

	back_value_type& back(void)
		{
		TOUCH_THREAD_ZONE(_back._tz);
		return _frnt._lt_back.front();
		}
	t_back_const_pass_value back(void)const
		{
		return const_cast<this_type&>(*this).back();
		}

	const signal* back_signal(void)const
		{
		TOUCH_THREAD_ZONE(_back._tz);
		return _frnt._signal;
		}

	front_value_type& front(void)
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
		return _back._lt_frnt.front();
		}
	t_frnt_const_pass_value front(void)const
		{
		return const_cast<this_type&>(*this).front();
		}

	const signal* front_signal(void)const
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
		return _back._signal;
		}

	void push_back(t_back_const_pass_value val)
		{
		TOUCH_THREAD_ZONE(_back._tz);
		_back._lt_back.push_back(val);
		}
	void push_front(t_frnt_const_pass_value val)
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
		_frnt._lt_frnt.push_back(val);
		}

	void pop_back(void)
		{
		TOUCH_THREAD_ZONE(_back._tz);
		_frnt._lt_back.pop_front();
		if ( _frnt._signal && _frnt._lt_midl.empty() && _frnt._lt_back.empty() )
			_frnt._signal->clr();
		}
	void pop_front(void)
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
		_back._lt_frnt.pop_front();
		if ( _back._signal && _back._lt_midl.empty() && _back._lt_frnt.empty() )
			_back._signal->clr();
		}

	void swap_back(void)
		{
		TOUCH_THREAD_ZONE(_back._tz);
			{
			bind_invoke(*_cs, enter(), leave());
			//	send info
			_back._lt_midl.splice(_back._lt_midl.end(), _back._lt_back);
			_frnt._lt_back.splice(_frnt._lt_back.end(), _frnt._lt_midl);
			if ( _back._signal && (!_back._lt_midl.empty() || !_back._lt_midl.empty()) )
				_back._signal->set();
			}
		}

	void swap_front(void)
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
			{
			bind_invoke(*_cs, enter(), leave());
			//	send info
			_frnt._lt_midl.splice(_frnt._lt_midl.end(), _frnt._lt_frnt);
			//	recv info
			_back._lt_frnt.splice(_back._lt_frnt.end(), _back._lt_midl);
			if ( _frnt._signal && (!_frnt._lt_back.empty() || !_frnt._lt_midl.empty()) )
				_frnt._signal->set();
			}
		}


	LOLIX_WARNING_FOR_PERFORMANCE("slower operator, O(n), use empty() instand?")
	size_type size_back(void)const
		{
		TOUCH_THREAD_ZONE(_back._tz);
		return _frnt._lt_back.size();
		}

	LOLIX_WARNING_FOR_PERFORMANCE("slower operator, O(n), use empty() instand?")
	size_type size_front(void)const
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
		return _back._lt_frnt.size();
		}

	bool empty_back(void)const
		{
		TOUCH_THREAD_ZONE(_back._tz);
		return _frnt._lt_back.empty();
		}

	bool empty_front(void)const
		{
		TOUCH_THREAD_ZONE(_frnt._tz);
		return _back._lt_frnt.empty();
		}
#endif	//	1

protected:
	template<typename _Ty, typename _Alc>
	struct _Tsb	//	Type swap buf
	{
		_Tsb<_Ty, _Alc>(void):_signal(0), _lt_frnt(), _lt_midl(), _lt_back(){}
		_Tsb<_Ty, _Alc>(const _Alc& alc):_signal(0), _lt_frnt(alc), _lt_midl(alc), _lt_back(alc){}
		_Tsb<_Ty, _Alc>(signal* ev): _signal(ev), _lt_frnt(), _lt_midl(), _lt_back()
			{
			if ( _signal )
				_signal->inc_ref();
			}

		_Tsb<_Ty, _Alc>(signal* ev, const _Alc& alc): _signal(ev), _lt_frnt(alc), _lt_midl(alc), _lt_back(alc)
			{
			if ( _signal )
				_signal->inc_ref();
			}

		~_Tsb<_Ty, _Alc>(void)
			{
			if ( _signal )
				_signal->release();
			}

		typedef	lolix::toy::list<_Ty, _Alc>	_T_Cnt_type;
		_T_Cnt_type _lt_frnt;	//	前台队列
		_T_Cnt_type _lt_midl;	//	中间队列
		_T_Cnt_type _lt_back;	//	后台队列
		signal* _signal;
		THREAD_ZONE		_tz;
	};

	_Tsb<_TyF, _TAlloc> _frnt;	//	frnt	>>>>>>>>>>>>>	back
	_Tsb<_TyB, _TAlloc> _back;	//	frnt	<<<<<<<<<<<<<	back
	critical_section* _cs;
public:
	const typename _Tsb<_TyF, _TAlloc>::_T_Cnt_type::allocator_type&	get_allocator(void)const
		{
		return _frnt._lt_frnt.get_allocator();
		}
};




template<typename _ITyF, typename _ITyB, typename _CS_FRONT, typename _CS_BACK, typename _CS_SWAP, typename _TAlloc>
class lolix::loli::_swap_list
{
	CANNT_COPY_LOLI;
/////////////////////////////////////////////////////////////
//				send					get
//	frnt		_frnt._lt_frnt			_back._lt_frnt
//
//	back		_back._lt_back			_frnt._lt_back
protected:
	typedef	typename _help::get_default_type<_ITyF, _ITyB>::frnt_type	_TyF;
	typedef	typename _help::get_default_type<_ITyF, _ITyB>::back_type	_TyB;

	typedef _swap_list<_ITyF, _ITyB, _CS_FRONT, _CS_BACK, _CS_SWAP, _TAlloc>	this_type;
	typedef typename lolix::type::type_def<_TyF>::const_reference				t_frnt_const_pass_value;
	typedef typename lolix::type::type_def<_TyB>::const_reference				t_back_const_pass_value;
public:
	typedef	_TAlloc		allocator_type;
	typedef size_type	size_type;
	typedef _TyF	front_value_type;
	typedef _TyB	back_value_type;
#if			1
	explicit _swap_list(const _CS_FRONT& cs_f, const _CS_BACK& cs_b, const _CS_SWAP& cs_s, signal* wait_frnt, signal* wait_back, const _TAlloc& alc)
		: _cs_b(cs_b)
		, _cs_f(cs_f)
		, _cs_s(cs_s)
		, _frnt(wait_back, alc)
		, _back(wait_frnt, alc)
		{
		}

	back_value_type& back(void)
		{
		bind_invoke(_cs_b, enter(), leave());
		return _frnt._lt_back.front();
		}
	t_back_const_pass_value back(void)const
		{
		return const_cast<this_type&>(*this).back();
		}

	signal* back_signal(void)
		{
		bind_invoke(_cs_b, enter(), leave());
		return _frnt._signal;
		}

	front_value_type& front(void)
		{
		bind_invoke(_cs_f, enter(), leave());
		return _back._lt_frnt.front();
		}
	t_frnt_const_pass_value front(void)const
		{
		return const_cast<this_type&>(*this).front();
		}

	signal* front_signal(void)
		{
		bind_invoke(_cs_f, enter(), leave());
		return _back._signal;
		}

	void push_back(t_back_const_pass_value val)
		{
		bind_invoke(_cs_b, enter(), leave());
		_back._lt_back.push_back(val);
		}
	void push_front(t_frnt_const_pass_value val)
		{
		bind_invoke(_cs_f, enter(), leave());
		_frnt._lt_frnt.push_back(val);
		}

	void pop_back(void)
		{
		bind_invoke(_cs_b, enter(), leave());
		_frnt._lt_back.pop_front();
		if ( _frnt._signal && _frnt._lt_midl.empty() && _frnt._lt_back.empty() )
			_frnt._signal->clr();
		}
	void pop_front(void)
		{
		bind_invoke(_cs_f, enter(), leave());
		_back._lt_frnt.pop_front();
		if ( _back._signal && _back._lt_midl.empty() && _back._lt_frnt.empty() )
			_back._signal->clr();
		}

	void swap_back(void)
		{
		bind_invoke(_cs_b, enter(), leave());
			{
			bind_invoke(_cs_s, enter(), leave());
			//	send info
			_back._lt_midl.splice(_back._lt_midl.end(), _back._lt_back);
			_frnt._lt_back.splice(_frnt._lt_back.end(), _frnt._lt_midl);
			if ( _back._signal && (!_back._lt_midl.empty() || !_back._lt_midl.empty()) )
				_back._signal->set();
			}
		}

	void swap_front(void)
		{
		bind_invoke(_cs_f, enter(), leave());
			{
			bind_invoke(_cs_s, enter(), leave());
			//	send info
			_frnt._lt_midl.splice(_frnt._lt_midl.end(), _frnt._lt_frnt);
			//	recv info
			_back._lt_frnt.splice(_back._lt_frnt.end(), _back._lt_midl);
			if ( _frnt._signal && (!_frnt._lt_back.empty() || !_frnt._lt_midl.empty()) )
				_frnt._signal->set();
			}
		}


	LOLIX_WARNING_FOR_PERFORMANCE("slower operator, O(n), use empty() instand?")
	size_type size_back(void)const
		{
		//bind_invoke(_cs_b, enter(), leave());
		return _frnt._lt_back.size() + _frnt._lt_midl.size() + _frnt._lt_frnt.size();
		}

	LOLIX_WARNING_FOR_PERFORMANCE("slower operator, O(n), use empty() instand?")
	size_type size_front(void)const
		{
		//bind_invoke(_cs_f, enter(), leave());
		return _back._lt_frnt.size() + _back._lt_midl.size() + _back._lt_back.size();
		}

	bool empty_back(void)const
		{
		//bind_invoke(_cs_b, enter(), leave());
		return _frnt._lt_back.empty() && _frnt._lt_midl.empty() && _frnt._lt_frnt.empty();
		}

	bool empty_front(void)const
		{
		//bind_invoke(_cs_f, enter(), leave());
		return _back._lt_frnt.empty() && _back._lt_midl.empty() && _back._lt_frnt.empty();
		}
#endif	//	1

protected:
	template<typename _Ty, typename _Alc>
	struct _Tsb	//	Type swap buf
	{
		CANNT_COPY_LOLI;
		_Tsb<_Ty, _Alc>(signal* ev, const _Alc& alc): _signal(ev), _lt_frnt(alc), _lt_midl(alc), _lt_back(alc)
			{
			if ( _signal )
				_signal->inc_ref();
			}

		~_Tsb<_Ty, _Alc>(void)
			{
			if ( _signal )
				_signal->release();
			}

		typedef	lolix::toy::list<_Ty, _Alc>	_T_Cnt_type;
		_T_Cnt_type _lt_frnt;	//	前台队列
		_T_Cnt_type _lt_midl;	//	中间队列
		_T_Cnt_type _lt_back;	//	后台队列
		signal* _signal;
	};

	_Tsb<_TyF, _TAlloc> _frnt;	//	frnt	>>>>>>>>>>>>>	back
	_Tsb<_TyB, _TAlloc> _back;	//	frnt	<<<<<<<<<<<<<	back

	mutable	_CS_BACK	_cs_b;
	mutable	_CS_FRONT	_cs_f;
	mutable	_CS_SWAP	_cs_s;
public:
	const typename _Tsb<_TyF, _TAlloc>::_T_Cnt_type::allocator_type&	get_allocator(void)const
		{
		return _frnt._lt_frnt.get_allocator();
		}
};


template<typename _ITyF, typename _ITyB, typename _TAlloc>
class lolix::loli::swap_list<_ITyF, _ITyB, lolix::THREAD_SAFE_SRMW, _TAlloc>
	: private _swap_list<_ITyF, _ITyB, _help::_LOGIC_CS<true>, _help::_LOGIC_CS<false>, _help::_LOGIC_CS<true>, _TAlloc>
{
	typedef swap_list<_ITyF, _ITyB, THREAD_SAFE_SRMW, _TAlloc>	this_type;
	typedef	_swap_list<_ITyF, _ITyB, _help::_LOGIC_CS<true>, _help::_LOGIC_CS<false>, _help::_LOGIC_CS<true>, _TAlloc>	base_type;
public:
	typedef	typename base_type::allocator_type	allocator_type;
	typedef typename base_type::size_type		size_type;
	typedef typename base_type::front_value_type	front_value_type;
	typedef typename base_type::back_value_type	back_value_type;
	enum { THREAD_SAFE_TYPE = THREAD_SAFE_SRMW };

	LOLIX_INLINE_CALL	swap_list(critical_section* fnt_cs, critical_section* swp_cs)
		: base_type(_help::_LOGIC_CS<true>(fnt_cs), _help::_LOGIC_CS<false>(), _help::_LOGIC_CS<true>(swp_cs), 0, 0, _TAlloc())
	{
	}

	LOLIX_INLINE_CALL	swap_list(critical_section* fnt_cs, critical_section* swp_cs, signal* wait_frnt, signal* wait_back)
		: base_type(_help::_LOGIC_CS<true>(fnt_cs), _help::_LOGIC_CS<false>(), _help::_LOGIC_CS<true>(swp_cs), wait_frnt, wait_back, _TAlloc())
	{
	}

	LOLIX_INLINE_CALL	swap_list(critical_section* fnt_cs, critical_section* swp_cs, const _TAlloc& alc)
		: base_type(_help::_LOGIC_CS<true>(fnt_cs), _help::_LOGIC_CS<false>(), _help::_LOGIC_CS<true>(swp_cs), 0, 0, alc)
	{
	}

	LOLIX_INLINE_CALL	swap_list(critical_section* fnt_cs, critical_section* swp_cs, signal* wait_frnt, signal* wait_back, const _TAlloc& alc)
		: base_type(_help::_LOGIC_CS<true>(fnt_cs), _help::_LOGIC_CS<false>(), _help::_LOGIC_CS<true>(swp_cs), wait_frnt, wait_back, alc)
	{
	}

	using base_type::back;
	using base_type::back_signal;
	using base_type::front;
	using base_type::front_signal;
	using base_type::push_back;
	using base_type::push_front;
	using base_type::pop_back;
	using base_type::pop_front;
	using base_type::swap_back;
	using base_type::swap_front;
	using base_type::size_back;
	using base_type::size_front;
	using base_type::empty_back;
	using base_type::empty_front;
	using base_type::get_allocator;
};

//--------------------------------------------------------------------------
//==============================================================================
#endif	//	!defined(__LOLIX__LOLI__SWAP_LIST__K_IN_G__)
